package cmd

import (
	"bytes"
	_ "embed"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"runtime"

	"dpm/internal/config"
	"dpm/pkg/tools"
	"dpm/pkg/version"

	"gopkg.in/yaml.v3"
)

// Run 执行命令
func Run() {
	// 定义帮助信息
	flag.Usage = func() {
		// 自定义帮助信息
		fmt.Println(helpText)
	}
	// 解析命令行参数
	flag.Parse()

	// 如果使用了 -v 选项, 则显示版本信息
	if *versionFlag {
		// 获取当前版本信息
		v := version.Get()
		// 打印版本信息 simple 格式
		if data, err := v.SprintVersion("simple"); err != nil {
			cl.PrintError(err)
			return
		} else {
			cl.Green(data)
			return
		}
	}

	if *versionLong {
		// 获取当前版本信息
		v := version.Get()
		// 打印版本信息 text 格式
		if data, err := v.SprintVersion("text"); err != nil {
			cl.PrintError(err)
			return
		} else {
			cl.Green(data)
			return
		}
	}

	// 根据子命令执行相应的操作, 第一个参数是子命令
	switch flag.Arg(0) {
	case "init", "i":
		// 初始化命令
		// 解析子命令参数, 从第二个参数开始解析(第一个参数是子命令)
		if err := initCmd.Parse(flag.Args()[1:]); err != nil {
			cl.PrintErrorf("解析子命令参数失败: %v", err)
			return
		}

		// 合并 -type 和 -t 选项的值
		initType, err := tools.MergeStringFlags(*initType, *initTypeShort)
		if err != nil {
			cl.PrintError(err)
			flag.Usage()
			return
		}

		// 根据初始化类型执行相应的操作
		switch initType {
		case "build", "b":
			// 合并 -name 和 -n 选项的值
			var (
				projectName string
				err         error
			)
			if projectName, err = tools.MergeStringFlags(*initName, *initNameLong); err != nil {
				cl.PrintError(err)
				return
			}

			// 如果没有指定项目名称, 则使用默认名称
			projectName = tools.FormatValue(projectName, "myapp")

			// 获取当前项目的版本信息
			defaultProjectVersion := tools.GetProjectVersion()

			// 如果指定了项目版本, 则更新配置文件
			projectVersion := tools.FormatValue(*initVersion, defaultProjectVersion)

			// 初始化构建配置文件
			if err := tools.InitConfig(defaultBuildPath, buildTemplate); err != nil {
				cl.PrintError(err)
				return
			}

			// 读取初始化的配置, 并更新项目名称和版本
			configData, err := os.ReadFile(defaultBuildPath)
			if err != nil {
				cl.PrintError(err)
				cl.PrintError("读取配置文件失败，请检查文件路径是否正确，或手动更新配置文件。")
				return
			}

			// 更新配置文件中的项目名称和版本
			configData = bytes.ReplaceAll(configData, []byte("{{name}}"), []byte(projectName))
			configData = bytes.ReplaceAll(configData, []byte("{{version}}"), []byte(projectVersion))

			// 将更新后的配置写入文件
			if err := os.WriteFile(defaultBuildPath, configData, 0644); err != nil {
				cl.PrintError(err)
				cl.PrintError("写入配置文件失败，请检查文件权限或磁盘空间是否足够。")
				return
			}
		case "version", "v":
			// 初始化版本信息文件
			// 检查当前目录是否存在 pkg 目录, 如果不存在则创建
			if err := tools.CheckAndCreateDir("pkg", true); err != nil {
				cl.PrintError(err)
				return
			}

			// 检查当前目录是否存在 version 目录, 如果不存在则创建
			if err := tools.CheckAndCreateDir(filepath.Join("pkg", "version"), true); err != nil {
				cl.PrintError(err)
				return
			}

			// 初始化版本信息包
			if err := tools.InitConfig(filepath.Join("pkg", "version", defaultVersionPath), versionTemplate); err != nil {
				cl.PrintError(err)
				return
			}

			// 打印初始化成功信息
			cl.PrintSuccess("初始化版本信息注入包成功, 请稍后在入口文件中引入pkg/version包, 并使用注入的版本信息!")
			return
		case "makeself", "m":
			// 初始化 makefile 自解压脚本

			// 获取安装路径, 如果没有指定则使用默认路径
			var makeSelfPath string
			makeSelfPath = *initPath
			if makeSelfPath == "" {
				makeSelfPath = defaultInstallPath
			}

			// 调用 initMakeself 函数初始化 makefile
			if err := initMakeself(makeSelfPath); err != nil {
				cl.PrintError(err)
				cl.PrintError("初始化makefile失败...")
				cl.PrintError("已退出...")
				return
			}
		case "package", "pack", "p":
			// 初始化 makefile 自解压打包配置文件
			if err := tools.InitConfig(defaultPackPath, packTemplate); err != nil {
				cl.PrintError(err)
				return
			}
		case "bashstd", "bsd":
			// 初始化 bash 标准脚本
			if err := initBashStd(); err != nil {
				cl.PrintError(err)
				cl.PrintError("初始化标准版bash开发脚本失败...")
				cl.PrintError("已退出...")
				return
			}
		case "bashmin", "bmd":
			// 初始化 bash 最小化脚本
			if err := initBashMin(); err != nil {
				cl.PrintError(err)
				cl.PrintError("初始化最小化版bash开发脚本失败...")
				cl.PrintError("已退出...")
			}
		default:
			// 如果没有指定初始化类型, 则显示帮助信息
			flag.Usage()
			return
		}
		// 确保退出
		return
	case "build", "b":
		// 构建命令
		// 解析子命令参数, 从第二个参数开始解析(第一个参数是子命令)
		if err := buildCmd.Parse(flag.Args()[1:]); err != nil {
			cl.PrintErrorf("解析子命令参数失败: %v", err)
			return
		}

		// 加载配置文件
		configBytes, err := tools.ReadConfigOrDefault(*buildCfgPath, defaultBuildPath)
		if err != nil {
			cl.PrintErrorf("读取配置文件失败: %v", err)
			return
		}

		// 解析配置文件
		var buildConfig config.Config
		if err := yaml.Unmarshal(configBytes, &buildConfig); err != nil {
			cl.PrintErrorf("解析配置文件失败: %v", err)
			return
		}

		// 执行构建命令
		if err := CompileAndBuild(buildConfig); err != nil {
			cl.PrintError(err)
			cl.PrintError("构建失败...")
			cl.PrintError("已退出构建...")
			return
		}
		return
	case "version":
		// 获取当前版本信息
		v := version.Get()
		// 打印版本信息
		if data, err := v.SprintVersion("text"); err != nil {
			cl.PrintError(err)
			return
		} else {
			cl.Green(data)
			return
		}
	case "package", "pack":
		// 打包命令
		// 解析子命令参数, 从第二个参数开始解析(第一个参数是子命令)
		if err := packageCmd.Parse(flag.Args()[1:]); err != nil {
			cl.PrintErrorf("解析子命令参数失败: %v", err)
			return
		}

		// 检查当前系统是否是Windows
		if runtime.GOOS == "windows" {
			cl.PrintError("当前系统是Windows, 不支持打包命令, 请在Linux或MacOS上执行打包命令")
			return
		}

		// 根据打包配置文件或参数打包应用程序
		if err := packCfgOrArgs(*packCfgPath); err != nil {
			cl.PrintError(err)
			cl.PrintError("打包失败...")
			cl.PrintError("已退出打包...")
			return
		}

		return
	default:
		// 没有指定子命令时，显示帮助信息
		flag.Usage()
		return
	}
}
